package com.lucas.lai.state.machine.squirrel.sample.one.machine;

/**
 * @author lucas.lai
 * @date 2023/11/9
 */
import com.lucas.lai.state.machine.squirrel.sample.one.context.OrderContext;
import com.lucas.lai.state.machine.squirrel.sample.one.envent.OrderEvent;
import com.lucas.lai.state.machine.squirrel.sample.one.service.OrderService;
import com.lucas.lai.state.machine.squirrel.sample.one.status.OrderState;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.squirrelframework.foundation.fsm.*;
import org.squirrelframework.foundation.fsm.annotation.*;
import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine;

/**
 * 定义业务具体的状态机 包含触发事件、状态变化时，调用的方法
 * @author lucas
 * @States 定义状态列表，里面可以包含多个状态
 * @State定义每个状态，name状态名称，entryStateInit进入状态时调用的方法，exitCallMethod 离开状态是调用的方法，initialState 为true时，为默认状态。
 * */
@States({
        @State(name = "INIT", entryCallMethod = "entryStateInit", exitCallMethod = "exitStateInit", initialState = true),
        @State(name = "WAIT_PAY", entryCallMethod = "entryStateWaitPay", exitCallMethod = "exitStateWaitPay"),
        @State(name = "WAIT_SEND", entryCallMethod = "entryStateWaitSend", exitCallMethod = "exitStateWaitSend"),
        @State(name = "PART_SEND", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend"),
        @State(name = "WAIT_RECEIVE", entryCallMethod = "entryStateWaitReceive", exitCallMethod = "exitStateWaitReceive"),
        @State(name = "COMPLETE", entryCallMethod = "entryStateComplete", exitCallMethod = "exitStateComplete")
})
@Transitions({
        @Transit(from = "INIT", to = "WAIT_PAY", on = "SUBMIT_ORDER", callMethod = "submitOrder"),
        @Transit(from = "INIT", to = "WAIT_SEND", on = "PAY", callMethod = "pay"),
        @Transit(from = "WAIT_PAY", to = "WAIT_SEND", on = "PAY", callMethod = "pay"),
        @Transit(from = "WAIT_SEND", to = "PART_SEND", on = "PART_SEND", callMethod = "partSend"),
        @Transit(from = "PART_SEND", to = "WAIT_RECEIVE", on = "SEND", callMethod = "send"),
        @Transit(from = "WAIT_RECEIVE", to = "COMPLETE", on = "COMPLETE", callMethod = "complete")
})
// @StateMachineParameters用来声明状态机泛型参数类型，向AbstractStateMachine传递参数
@StateMachineParameters(stateType = OrderState.class, eventType = OrderEvent.class, contextType = OrderContext.class)
@Slf4j
public class OrderStateMachine extends AbstractStateMachine<UntypedStateMachine, Object, Object, Object> implements UntypedStateMachine {

    private OrderService orderService;

    protected ApplicationContext applicationContext;

    //定义构造函数接受ApplicationContext注入
    public OrderStateMachine(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.orderService = applicationContext.getBean(OrderService.class);
    }

    // 状态转换时调用的方法，需要将方法名配置在 callMethod 内
    // 若【方法名】符合 transitFrom[fromStateName]To[toStateName] 格式，不需要配置 callMethod
    public void submitOrder(OrderState fromState, OrderState toState, OrderEvent event, OrderContext context) {
        log.info("转换事件 {}=>{} on {} with {}.", fromState, toState, event, context);
        orderService.submitOrder(toState);
    }


    public void complete(OrderState fromState, OrderState toState, OrderEvent event, OrderContext context) {
        log.info("complete转换事件 {}=>{} on {} with {}.", fromState, toState, event, context);
    }

    // 符合 entry[StateName] 格式，不需要配置 callMethod
    public void entryStateInit(OrderState fromState, OrderState toState, OrderEvent event, OrderContext context) {
        log.info("进入状态 {}=>{} on {} with {}.", fromState, toState, event, context);
    }

    public void exitStateInit(OrderState fromState, OrderState toState, OrderEvent event, OrderContext context) {
        log.info("退出状态 {}=>{} on {} with {}.", fromState, toState, event, context);
    }



    public void pay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("执行事件方法pay {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
        orderService.goPay(toState, orderContext.getOrderDTO());
    }

    public void partSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("执行事件方法partSend {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void send(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("执行事件方法send {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }


    public void entryStateWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("进入状态entryStateWaitPay {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void exitStateWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("退出状态exitStateWaitPay {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);

    }

    public void entryStateWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("进入状态entryStateWaitSend {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void exitStateWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("退出状态exitStateWaitSend{}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);

    }

    public void entryStatePartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("进入状态entryStatePartSend {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void exitStatePartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("进入状态exitStatePartSend {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void entryStateWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("进入状态entryStateWaitReceive {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void exitStateWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("退出状态exitStateWaitReceive {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void entryStateComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("进入状态entryStateComplete {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }

    public void exitStateComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) {
        log.info("退出状态exitStateComplete {}=>{} on {} with {}.", fromState, toState, orderEvent, orderContext);
    }



    /**
     * 如果不想用 OrderStatusEventListener 这种声明在单独类里的方法，可以直接重写以下方法，效果是一样的
     * @param fromState
     * @param toState
     * @param event
     * @param context
     */
    @Override
    protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {
        /**
         * 当状态转换过程中出现异常，已执行的action将失效并且状态机会进入error状态，意思就是状态机实例不会再处理任何event。
         * 假如用户继续向状态机发送event，便会抛出IllegalStateException异常。所有状态转换过程中发生的异常，包括action执行和外部listener调用，会被包装成TransitionException（未检查异常）
         * 目前，默认的异常处理策略非常简单并且粗暴的连续抛出异常，可以参阅AbstractStateMachine.afterTransitionCausedException方法。
         */
        log.info("执行事件 发生异常 {}", getLastException().getMessage());
        Throwable targeException = getLastException().getTargetException();
        if(targeException instanceof IllegalArgumentException &&
                fromState.equals("A") && toState.equals("B") && event.equals("ToB")) {
            //当满足某些条件时 可执行
            setStatus(StateMachineStatus.IDLE);
        }  else {
            super.afterTransitionCausedException(fromState, toState, event, context);
        }
    }

   /* @Override
    protected void beforeTransitionBegin(Object fromState, Object event, Object context) {
        // 转换开始时被调用
//        super.beforeTransitionBegin(fromState, event, context);
        log.info("Override beforeTransitionBegin");
    }

    @SneakyThrows
    @Override
    protected void afterTransitionCompleted(Object fromState, Object toState, Object event, Object context) {
        // 转换完成时被调用
//        super.afterTransitionCompleted(fromState, toState, event, context);
        log.info("Override afterTransitionCompleted");
    }*/

    /*@Override
    protected void afterTransitionEnd(Object fromState, Object toState, Object event, Object context) {
        // 转换结束时被调用
        //       super.afterTransitionEnd(fromState, toState, event, context);
        log.info("Override afterTransitionEnd");
    }
    @Override
    protected void afterTransitionDeclined(Object fromState, Object event, Object context) {
        // 当转换被拒绝时被调用。实际是调用 callMethod 中的方法被调用时，抛出异常时被调用
//        super.afterTransitionDeclined(fromState, event, context);
        log.info("Override afterTransitionDeclined");
    }*/

   /* @Override
    protected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) {
        // 当转换开始时被调用。实际是 callMethod 中的方法被调用时，先调用该方法。类似于 AOP 的效果
        //       super.beforeActionInvoked(fromState, toState, event, context);
        log.info("Override beforeActionInvoked");
    }*/

   /* @Override
    protected void afterActionInvoked(Object fromState, Object toState, Object event, Object context) {
        // 当转换结束时被调用。实际是 callMethod 被调用后，调用该方法。类似于 AOP 的效果
        //       super.afterActionInvoked(fromState, toState, event, context);
        log.info("Override afterActionInvoked");
    }*/
}
